-
Notifications
You must be signed in to change notification settings - Fork 637
support x402 v2 headers #8623
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support x402 v2 headers #8623
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: f458196 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughAdds x402 v2 support: introduces versioned header constants and helpers, a v2 header encoding function, schema/type updates to accept v2, and makes header selection and x402Version handling dynamic across decode, fetch, verify, and settle flows. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Server
participant Facilitator
Client->>Server: Initial request (no payment)
Server->>Client: 402 + payment header (name from getPaymentRequestHeader(x402Version))
Client->>Facilitator: Payment attempt (sends PAYMENT-SIGNATURE / X-PAYMENT header per version)
Facilitator->>Server: Settlement call (includes payment data + x402Version)
Server->>Server: decodePaymentRequest (preserve client x402Version if present)
Server->>Client: Accept original request retry + payment response header (name from getPaymentResponseHeader)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/thirdweb/src/x402/headers.ts (1)
8-10: Consider stricter version validation to avoid silent fallback.The
resolveVersionfunction silently converts any non-1 value (including 0, 3, or other invalid numbers) to version 2. While the type signature acceptsnumber | X402Version, invalid inputs are masked rather than caught.Consider throwing for unsupported versions or validating against
supportedX402Versions:♻️ Suggested stricter validation
+import { type X402Version, x402Version, supportedX402Versions } from "./types.js"; + function resolveVersion(version?: number | X402Version): X402Version { - return version === 1 ? 1 : 2; + if (version === undefined) { + return x402Version; + } + if (!supportedX402Versions.includes(version as X402Version)) { + throw new Error(`Unsupported x402 version: ${version}`); + } + return version as X402Version; }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
packages/thirdweb/src/x402/common.tspackages/thirdweb/src/x402/fetchWithPayment.test.tspackages/thirdweb/src/x402/fetchWithPayment.tspackages/thirdweb/src/x402/headers.tspackages/thirdweb/src/x402/schemas.tspackages/thirdweb/src/x402/settle-payment.tspackages/thirdweb/src/x402/types.tspackages/thirdweb/src/x402/verify-payment.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoidanyandunknownin TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.) in TypeScript
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose
Files:
packages/thirdweb/src/x402/fetchWithPayment.test.tspackages/thirdweb/src/x402/schemas.tspackages/thirdweb/src/x402/common.tspackages/thirdweb/src/x402/fetchWithPayment.tspackages/thirdweb/src/x402/types.tspackages/thirdweb/src/x402/headers.tspackages/thirdweb/src/x402/settle-payment.tspackages/thirdweb/src/x402/verify-payment.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.{ts,tsx}: Place tests alongside code:foo.ts↔foo.test.tsin the same directory
Use real function invocations with stub data in tests; avoid brittle mocks
Use Mock Service Worker (MSW) for fetch/HTTP call interception in tests
Keep tests deterministic and side-effect free
Use predefined test accounts fromtest/src/test-wallets.tsin tests
UseFORKED_ETHEREUM_CHAINfor mainnet interactions andANVIL_CHAINfor isolated tests
**/*.test.{ts,tsx}: Co-locate tests with source files using the pattern foo.ts ↔ foo.test.ts
Use real function invocations with stub data in tests; avoid brittle mocks
For network interactions in tests, use Mock Service Worker (MSW) to intercept fetch/HTTP calls, mocking only scenarios that are hard to reproduce
Keep tests deterministic and side-effect free; Vitest is pre-configured
Files:
packages/thirdweb/src/x402/fetchWithPayment.test.ts
packages/thirdweb/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g.const { jsPDF } = await import("jspdf");)Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)
Files:
packages/thirdweb/src/x402/fetchWithPayment.test.tspackages/thirdweb/src/x402/schemas.tspackages/thirdweb/src/x402/common.tspackages/thirdweb/src/x402/fetchWithPayment.tspackages/thirdweb/src/x402/types.tspackages/thirdweb/src/x402/headers.tspackages/thirdweb/src/x402/settle-payment.tspackages/thirdweb/src/x402/verify-payment.ts
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Biome governs formatting and linting; its rules live in biome.json. Run
pnpm fix&pnpm lintbefore committing, ensure there are no linting errors
Files:
packages/thirdweb/src/x402/fetchWithPayment.test.tspackages/thirdweb/src/x402/schemas.tspackages/thirdweb/src/x402/common.tspackages/thirdweb/src/x402/fetchWithPayment.tspackages/thirdweb/src/x402/types.tspackages/thirdweb/src/x402/headers.tspackages/thirdweb/src/x402/settle-payment.tspackages/thirdweb/src/x402/verify-payment.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Lazy-import optional features; avoid top-level side-effects
Files:
packages/thirdweb/src/x402/fetchWithPayment.test.tspackages/thirdweb/src/x402/schemas.tspackages/thirdweb/src/x402/common.tspackages/thirdweb/src/x402/fetchWithPayment.tspackages/thirdweb/src/x402/types.tspackages/thirdweb/src/x402/headers.tspackages/thirdweb/src/x402/settle-payment.tspackages/thirdweb/src/x402/verify-payment.ts
🧬 Code graph analysis (6)
packages/thirdweb/src/x402/fetchWithPayment.test.ts (1)
packages/thirdweb/src/x402/headers.ts (1)
getPaymentRequestHeader(12-17)
packages/thirdweb/src/x402/common.ts (1)
packages/thirdweb/src/x402/types.ts (1)
x402Version(16-16)
packages/thirdweb/src/x402/fetchWithPayment.ts (2)
packages/thirdweb/src/x402/types.ts (1)
x402Version(16-16)packages/thirdweb/src/x402/headers.ts (2)
getPaymentRequestHeader(12-17)getPaymentResponseHeader(19-26)
packages/thirdweb/src/x402/headers.ts (1)
packages/thirdweb/src/x402/types.ts (2)
X402Version(15-15)x402Version(16-16)
packages/thirdweb/src/x402/settle-payment.ts (2)
packages/thirdweb/src/x402/headers.ts (1)
getPaymentResponseHeader(19-26)packages/thirdweb/src/x402/types.ts (1)
x402Version(16-16)
packages/thirdweb/src/x402/verify-payment.ts (1)
packages/thirdweb/src/x402/types.ts (1)
x402Version(16-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Unit Tests
- GitHub Check: Build Packages
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (17)
packages/thirdweb/src/x402/headers.ts (1)
12-26: LGTM!The header resolution functions are well-structured with clear return types. The default fallback to
x402Versionwhen no version is provided ensures backward compatibility.packages/thirdweb/src/x402/types.ts (2)
14-16: LGTM!The versioning implementation using
as constwith a derived type provides type safety while keeping the supported versions maintainable. The default version set to 2 aligns with the PR objective of supporting x402 v2 headers.
28-31: LGTM!The JSDoc update accurately documents both header names (PAYMENT-SIGNATURE for v2, X-PAYMENT for v1), which improves discoverability for developers.
packages/thirdweb/src/x402/common.ts (1)
54-55: LGTM!The nullish coalescing assignment (
??=) correctly preserves the client-provided version while defaulting to the current protocol version when missing. This is essential for proper multi-version support where clients may send either v1 or v2 payments.packages/thirdweb/src/x402/fetchWithPayment.test.ts (3)
4-4: LGTM!Good addition of the
getPaymentRequestHeaderimport to enable dynamic header validation in tests.
113-117: LGTM!The assertion now properly validates that the payment header name is dynamically determined based on the
x402Versionfrom the mock response. This ensures the implementation correctly handles version-specific headers.
307-311: Good backward compatibility test coverage.This test validates that v1 payloads (with
x402Version: 1in the base64-encoded header) correctly use the v1 header name (X-PAYMENT). This ensures backward compatibility with existing v1 servers.packages/thirdweb/src/x402/verify-payment.ts (2)
32-34: LGTM!The JSDoc example correctly demonstrates the header fallback pattern (v2
payment-signaturefirst, then v1x-payment), providing clear guidance for implementers.
126-126: LGTM!Using
decodedPayment.x402Version ?? x402Versionin error responses ensures the 402 response uses the same protocol version as the client's request. This maintains consistency and allows clients to properly interpret error responses.Also applies to: 142-142
packages/thirdweb/src/x402/schemas.ts (1)
85-85: LGTM!The schema correctly expands to accept both X402 protocol versions using a union of literals, maintaining strict type validation while enabling v2 support.
packages/thirdweb/src/x402/settle-payment.ts (4)
4-4: LGTM!Import correctly added for dynamic header name resolution.
41-43: LGTM!Example code correctly demonstrates reading payment data from both v2 (
payment-signature) and v1 (x-payment) headers with appropriate fallback for backward compatibility.Also applies to: 110-111
158-173: LGTM!The dynamic header name resolution correctly uses the client's provided
x402Versionfrom the decoded payment, ensuring the response header matches the version the client used in their request.
184-184: Verify the default version fallback behavior in error responses.The nullish coalescing
decodedPayment.x402Version ?? x402Versionfalls back to the default version (v2) whenx402Versionis missing from the decoded payment. This means error responses may advertise v2 even if the client originally used v1 but didn't include the version field.If this is intentional (to encourage clients to upgrade), the current implementation is fine. Otherwise, consider preserving the version from the original 402 response requirements if available.
Also applies to: 200-200
packages/thirdweb/src/x402/fetchWithPayment.ts (3)
8-11: LGTM!Clean imports with appropriate aliasing. Renaming to
defaultX402Versionclearly distinguishes the module-level default from the locally-scopedx402Versionvariable parsed from responses.Also applies to: 20-20
104-104: LGTM!Fallback to
defaultX402Versionensures backward compatibility with servers that don't includex402Versionin their 402 responses. This correctly defaults to v2 for such cases.Also applies to: 122-122
188-202: LGTM!Dynamic header name resolution correctly uses the version from the server's 402 response, ensuring the payment request and expected response headers match the protocol version the server indicated.
size-limit report 📦
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #8623 +/- ##
==========================================
- Coverage 53.00% 52.97% -0.04%
==========================================
Files 929 932 +3
Lines 62109 62270 +161
Branches 4077 4095 +18
==========================================
+ Hits 32921 32987 +66
- Misses 29089 29184 +95
Partials 99 99
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
.changeset/eight-pants-drum.md (1)
1-5: Consider a more descriptive changeset message.The current description "Support x402 v2" is minimal. Consider expanding it to briefly explain what x402 v2 support includes (e.g., "Add support for x402 v2 protocol with backward compatibility for v1, including versioned headers and dynamic header selection").
Additionally, verify whether this should be a
minorversion bump rather thanpatch, as adding support for a new protocol version typically constitutes a feature addition rather than a bug fix.📝 More descriptive changeset example
--- "thirdweb": patch --- -Support x402 v2 +Add x402 v2 protocol support with backward compatibility for v1, including versioned headers and dynamic version detection
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
.changeset/eight-pants-drum.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Build Packages
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @apps/portal/src/app/x402/server/page.mdx:
- Line 214: Update the Express and Hono examples to use the v2-first,
v1-fallback header pattern like the page code does: replace the single v1 header
usage with a fallback expression that checks "payment-signature" first then
"x-payment" (apply this to the Express example where req.headers is accessed and
to the Hono example where c.req.header(...) is used), ensuring the paymentData
assignment mirrors the behavior of the const paymentData =
request.headers.get("PAYMENT-SIGNATURE") || request.headers.get("X-PAYMENT")
line.
- Line 386: Update the Express and Hono middleware examples so they read the
same two headers as the Next.js example: change the Express case where
paymentData is sourced from req.headers["x-payment"] to check both
req.headers["payment-signature"] and req.headers["x-payment"], and change the
Hono example where paymentData uses c.req.header("x-payment") to check both
c.req.header("payment-signature") and c.req.header("x-payment"); locate the
occurrences by searching for the paymentData variable and the uses of
req.headers and c.req.header in the middleware examples and apply the same
header precedence as the Next.js snippet.
🧹 Nitpick comments (2)
packages/thirdweb/src/x402/encode.ts (1)
50-63: Consider extracting the inline type for reusability.The function implementation is correct and follows existing patterns. However, the inline parameter type is moderately complex. If this shape is used elsewhere (e.g., in
common.tsfor v2 response formatting), consider extracting it to a shared type alias intypes.tsfor consistency and reuse.♻️ Optional: Extract type alias
// In types.ts or schemas.ts export type PaymentRequiredPayload = { x402Version: number; error?: string; accepts: RequestedPaymentRequirements[]; resource?: { url: string; description?: string; mimeType?: string }; };Then update the function signature:
-export function encodePaymentRequired(paymentRequired: { - x402Version: number; - error?: string; - accepts: RequestedPaymentRequirements[]; - resource?: { url: string; description?: string; mimeType?: string }; -}): string { +export function encodePaymentRequired( + paymentRequired: PaymentRequiredPayload, +): string {packages/thirdweb/src/x402/types.ts (1)
93-98: Consider adding a discriminant field for easier type narrowing.The union type works but consumers might benefit from a discriminant. Currently, narrowing requires checking
responseBodystructure. A version discriminant could simplify this.One approach would be to add a
versiondiscriminant field:type PaymentRequiredResultV1 = { version: 1; // ... existing fields }; type PaymentRequiredResultV2 = { version: 2; // ... existing fields };This would allow cleaner narrowing:
if (result.version === 1) { // TypeScript knows this is V1 }However, this may conflict with existing API contracts, so the current approach is acceptable if discriminant-based narrowing isn't needed by consumers.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (12)
apps/playground-web/src/app/api/paywall/route.tsapps/portal/src/app/x402/facilitator/page.mdxapps/portal/src/app/x402/page.mdxapps/portal/src/app/x402/server/page.mdxpackages/nexus/src/settle-payment.tspackages/nexus/src/verify-payment.tspackages/thirdweb/src/x402/common.tspackages/thirdweb/src/x402/encode.tspackages/thirdweb/src/x402/facilitator.tspackages/thirdweb/src/x402/fetchWithPayment.tspackages/thirdweb/src/x402/settle-payment.tspackages/thirdweb/src/x402/types.ts
✅ Files skipped from review due to trivial changes (2)
- packages/nexus/src/settle-payment.ts
- packages/nexus/src/verify-payment.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoidanyandunknownin TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.) in TypeScript
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose
Files:
apps/playground-web/src/app/api/paywall/route.tspackages/thirdweb/src/x402/encode.tspackages/thirdweb/src/x402/types.tspackages/thirdweb/src/x402/fetchWithPayment.tspackages/thirdweb/src/x402/settle-payment.tspackages/thirdweb/src/x402/common.tspackages/thirdweb/src/x402/facilitator.ts
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Usecn()from@/lib/utilsfor conditional Tailwind class merging
Use design system tokens for styling (backgrounds:bg-card, borders:border-border, muted text:text-muted-foreground)
ExposeclassNameprop on root element for component overrides
Files:
apps/playground-web/src/app/api/paywall/route.ts
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Biome governs formatting and linting; its rules live in biome.json. Run
pnpm fix&pnpm lintbefore committing, ensure there are no linting errors
Files:
apps/playground-web/src/app/api/paywall/route.tspackages/thirdweb/src/x402/encode.tspackages/thirdweb/src/x402/types.tspackages/thirdweb/src/x402/fetchWithPayment.tspackages/thirdweb/src/x402/settle-payment.tspackages/thirdweb/src/x402/common.tspackages/thirdweb/src/x402/facilitator.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Lazy-import optional features; avoid top-level side-effects
Files:
apps/playground-web/src/app/api/paywall/route.tspackages/thirdweb/src/x402/encode.tspackages/thirdweb/src/x402/types.tspackages/thirdweb/src/x402/fetchWithPayment.tspackages/thirdweb/src/x402/settle-payment.tspackages/thirdweb/src/x402/common.tspackages/thirdweb/src/x402/facilitator.ts
packages/thirdweb/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g.const { jsPDF } = await import("jspdf");)Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)
Files:
packages/thirdweb/src/x402/encode.tspackages/thirdweb/src/x402/types.tspackages/thirdweb/src/x402/fetchWithPayment.tspackages/thirdweb/src/x402/settle-payment.tspackages/thirdweb/src/x402/common.tspackages/thirdweb/src/x402/facilitator.ts
🧬 Code graph analysis (5)
packages/thirdweb/src/x402/encode.ts (1)
packages/thirdweb/src/x402/schemas.ts (1)
RequestedPaymentRequirements(40-42)
packages/thirdweb/src/x402/types.ts (2)
packages/thirdweb/src/exports/x402.ts (2)
PaymentArgs(18-18)WaitUntil(12-12)packages/thirdweb/src/x402/facilitator.ts (1)
WaitUntil(19-19)
packages/thirdweb/src/x402/fetchWithPayment.ts (2)
packages/thirdweb/src/x402/types.ts (1)
x402Version(16-16)packages/thirdweb/src/x402/headers.ts (2)
getPaymentRequestHeader(12-17)getPaymentResponseHeader(19-26)
packages/thirdweb/src/x402/settle-payment.ts (3)
packages/thirdweb/src/x402/headers.ts (1)
getPaymentResponseHeader(19-26)packages/thirdweb/src/x402/encode.ts (1)
safeBase64Encode(71-79)packages/thirdweb/src/x402/types.ts (1)
x402Version(16-16)
packages/thirdweb/src/x402/facilitator.ts (1)
packages/thirdweb/src/x402/types.ts (2)
PaymentRequiredResultV1(59-79)x402Version(16-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Unit Tests
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Lint Packages
- GitHub Check: Build Packages
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (22)
apps/playground-web/src/app/api/paywall/route.ts (1)
30-32: LGTM!The header fallback logic correctly prioritizes the v2
PAYMENT-SIGNATUREheader while preserving backward compatibility with v1'sX-PAYMENT. This aligns well with the broader x402 v2 support being added across the codebase.apps/portal/src/app/x402/facilitator/page.mdx (1)
106-106: LGTM!The header fallback order correctly prioritizes the v2 header (
PAYMENT-SIGNATURE) while maintaining backward compatibility with v1 (X-PAYMENT).packages/thirdweb/src/x402/fetchWithPayment.ts (3)
8-11: LGTM!Clean imports for header utilities and version default. The separation of header logic into a dedicated module improves maintainability.
Also applies to: 20-20
103-103: LGTM!Defaulting
x402VersiontodefaultX402Versionwhen absent from the response ensures backward compatibility with servers that don't explicitly include the version field.Also applies to: 121-121
187-201: LGTM!Dynamic header name resolution based on
x402Versionis computed once and applied consistently to both the request header andAccess-Control-Expose-Headers. This ensures the correct version-specific headers are used throughout the request lifecycle.apps/portal/src/app/x402/page.mdx (1)
116-116: LGTM!Documentation correctly updated to prioritize the v2
PAYMENT-SIGNATUREheader with fallback to v1X-PAYMENT.packages/thirdweb/src/x402/encode.ts (1)
2-5: LGTM!Import extended appropriately to include the
RequestedPaymentRequirementstype needed for the new encoding function.packages/thirdweb/src/x402/settle-payment.ts (4)
4-4: LGTM!Dynamic header name resolution correctly derives from
decodedPayment.x402Version, ensuring the response uses the same header convention as the incoming request.Also applies to: 158-160
167-175: LGTM!Success response correctly uses the dynamic header name for both
Access-Control-Expose-Headersand the actual payment response header key.
184-184: LGTM!Error responses correctly preserve the client's
x402Versionwith a fallback to the current protocol version. This ensures consistent version handling across success and error paths.Also applies to: 200-200
41-43: LGTM!JSDoc examples updated to reflect the v2 header priority with v1 fallback, consistent with the documentation changes in the portal.
Also applies to: 110-111
packages/thirdweb/src/x402/common.ts (5)
35-54: LGTM! Clean v2 response formatter.The helper function properly encapsulates v2 header-based format with base64 encoding via
encodePaymentRequired. The emptyresponseBodycast toRecord<string, never>correctly represents the v2 format.
59-74: LGTM! Consistent v1 response formatter.The v1 helper correctly returns a body-based response with
Content-Type: application/jsonand the payment requirements in the body.
91-98: LGTM! Sensible default to v2 format.Defaulting to v2 format when no payment header is present is appropriate since newer clients should receive the modern header-based format.
104-105: LGTM! Correct version preservation using nullish coalescing.The
??=operator correctly preserves any client-provided version while defaulting to the current protocol version when absent.
122-136: LGTM! Version-aware error response formatting.Respecting the client's x402 version when returning error responses ensures clients receive responses in the format they can process.
packages/thirdweb/src/x402/facilitator.ts (2)
13-17: LGTM! Type signature correctly narrowed to V1.The
acceptsmethod return type is appropriately narrowed toPaymentRequiredResultV1since the API endpoint returns the v1 body-based format. This provides better type safety for consumers.Also applies to: 55-57
269-307: LGTM! Accepts method correctly includes version in request.The implementation properly sends
x402Versionto the server and types the response correctly as V1 format.packages/thirdweb/src/x402/types.ts (4)
14-16: LGTM! Clean version type derivation.The
as consttuple pattern correctly derivesX402Versionas a union type1 | 2, and the default export is set to the current protocol version.
48-49: LGTM! Optional version field with clear documentation.The optional
x402Versionfield allows clients to specify their preferred version while defaulting to v2 for new integrations.
56-79: LGTM! Comprehensive V1 result type.The V1 type correctly captures the body-based response format with all necessary error details and optional fields for enhanced error handling.
81-91: LGTM! Clean V2 result type with empty body constraint.The
Record<string, never>type correctly enforces that V2 responses carry payment requirements in headers, not the body.
PR-Codex overview
This PR focuses on updating the
thirdwebpayment protocol to support version 2 (x402 v2), enhancing header handling for payment requests and responses, and improving the overall payment processing flow.Detailed summary
x402Versionto support both 1 and 2.PAYMENT-SIGNATUREoverX-PAYMENT.headers.tsfor handling payment request and response headers.Summary by CodeRabbit
New Features
Improvements
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.